#ifndef __SHOP_SCHEDULER__
#define __SHOP_SCHEDULER__
//#include "../src/types.hh"
//#include "../src/timer.hh"
#include "../src/shopSolver.hh"


/**
 * \file shopScheduler.hh
 * \author Jiri Cigler
 * \brief Declaration of ShopType enum and ShopScheduler 
 * \see ShopScheduler
 * \see ShopType 
 */
/**
 * \brief Specifies type of shop problem ( open, flow job shop .. ). It
 * specifies precedence constrains between tasks.
 */
enum ShopType{
	ST_JOBSHOP,/**< for solving job shop problem*/
	ST_OPENSHOP,/**< for solving open shop problem*/
	ST_FLOWSHOP /**< for solving flow shop problem*/
};

using namespace std;
using namespace Gecode;


/**
 * \brief ShopScheduler is class for preparing data for solving shop
 * problems.
 *
 * 
 */
class ShopScheduler{

	/** \brief List of all tasks to be scheduled
	* \see Task
	* \see std
	*/
	vector<Task> taskList;
	
	/**
	 * \brief Vector for holding correct index of each task after reindexing
	 * \see SortTableElement
	 * \see std
	 */
	vector<SortTableElement> sortTable;
	
	///If true, program prints more information
	bool verbose;

	public:	
	///Array of functions for sorting of tasks
//	static const bool(ShopScheduler:: *SORTFUNCPTR[])(const Task &a, const Task &b);

	///number of sorting methods
//	static const unsigned int SORTFUNCPTRSIZE;
	protected:
	/**
	 * \brief Reindex list of tasks for trying to minimize runtime
	 * of searching for solution.
	 *\param sortFunc index of method (from array sortFunctPtr ) to be used  for reindexing
	 */
	void reindex(int sortFunc);


	/**
	 *\brief Fill  in list of tasks and set up precedence constraints
	 * \param shopType Specifies shop type ( for correct precedence
	 * constrains. 
	 * \param processor - reference to array which define dedicated processor for each
	 * element ( task ). Rows of array defines Jobs, columns tasks
	 * in job. Dimension must be same as dimension of processingTime
	 * \param processingTime - reference to array which define processing
	 * time of each element (task). Rows of array defines Jobs, columns tasks
	 * in job. dimension must be same as dimension of processor.
	 * \param jobs number of jobs ( number of rows of processor
	 * matrix )
	 * \param tasksInJob Number of tasks in job ( columns of
	 * processor matrix )
	 */
	void init(ShopType shopType, int **& processor, unsigned int **& processingTime, int jobs, int tasksInJob);


	/**
	 * \brief Return minimal estimated time for solution. It is the
	 * biggest time  from times that take jobs.
	 * \param processor - reference to array which define dedicated processor for each
	 * element ( task ). Rows of array defines Jobs, columns tasks
	 * in job. Dimension must be same as dimension of processingTime
	 * \param processingTime - reference to array which define processing
	 * time of each element (task). Rows of array defines Jobs, columns tasks
	 * in job. dimension must be same as dimension of processor.
	 * \param jobs number of jobs ( number of rows of processor
	 * matrix )
	 * \param tasksInJob Number of tasks in job ( columns of
	 * processor matrix )
	 * \param processors number of processors in the problem
	 * \return minimal time of solution.
	 */

	unsigned int getMinTime(int **&processor, unsigned int **& processingTime, int jobs, int tasksInJob, int processors );

	 /**
	 * \brief Return maximal estimated time for solution. It is a
	 * sum of all task's processing times.
	 * \param processingTime - reference to array which define processing
	 * time of each element (task). Rows of array defines Jobs, columns tasks
	 * in job. dimension must be same as dimension of processor.
	 * \param jobs number of jobs ( number of rows of processor
	 * matrix )
	 * \param tasksInJob Number of tasks in job ( columns of
	 * processor matrix )
	 * \return maximal time of solution.
	 */
	unsigned int getMaxTime(unsigned int **&processingTime, int jobs, int tasksInJob);
	

public:	
	/**
	 * \brief Main method for searching for solution 
	 * \param shopType Specifies shop type ( for correct precedence
	 * constrains. 
	 * \param processor Reference to array which define dedicated processor for each
	 * element ( task ). Rows of array defines Jobs, columns tasks
	 * in job. Dimension must be same as dimension of processingTime
	 * \param processingTime - reference to array which define processing
	 * time of each element (task). Rows of array defines Jobs, columns tasks
	 * in job. dimension must be same as dimension of processor.
	 * \param jobs number of jobs ( number of rows of processor
	 * matrix )
	 * \param tasksInJob Number of tasks in job ( columns of
	 * processor matrix )
	 * \param result array of same dimension as dimension of
	 * processor. Result will be returned in this variable.
	 * \param runtime Runtime of scheduler.
	 * \param processors number of processors 
	 *
	 */
	void run(ShopType shopType,
			int **& processor,
			 unsigned int **& processingTime,
			 const  int jobs,
			 int tasksInJob,
			 int processors ,
			 unsigned int **& result,
			double * runtime) ;


	/**
	 * \brief Constructor of class
	 * \param verbose true if you want verbose mode
	 */
	ShopScheduler(bool verbose);

};
/**
 * \brief Sort tasks from the max processing time to min
 * processing time
 */
bool DescendingProcessingTimeSort(const Task& a,const Task& b);
/**
 * \brief Sort tasks from the min dediceted resource to max d.r.
 */
bool AscendingResourceSort(const Task& a, const Task& b);

/**
 *\brief Sort tasks from tasks with the biggest number of prerequirements to smallest.
 */
bool DescendingNumberOfPrerequirementsSort( const Task& a,const Task& b);
/**
 * \brief Sort combining many aspects for searching
 */
bool ComplexSort( const Task& a,const Task& b);


#include "../src/shopScheduler.icc"
#endif
